/*oOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoO*/
/*
Authors: Ram Ovadia 201374022 and Lior Fass 300069705
Project: HW Assignment 4 
Description: This is the implementation of the module implementing the roadmap object of Oiway.  
*/
/*oOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoO*/

#include "map.h"


Map *map_init(int n)
{
	Map *map;
	map = (Map *)malloc(sizeof(Map));
	if (map == NULL)
	{
		printf("Failed to allocate map\r\n");
		return NULL;
	}

	if (n < 1)
	{
		printf("invalid dimension size n\r\n");
		return NULL;
	}
	map->n = n;

	map->graph = (int *)malloc(sizeof(int)*n*n);
	if (map->graph == NULL)
	{
		printf("Failed to allocate map graph\r\n");
		return NULL;
	}

	map->map_index = (Node *)malloc(sizeof(Node)*n);
	if (map->map_index == NULL)
	{
		printf("Failed to allocate map index\r\n");
		return NULL;
	}

	return map;
}


void map_clean(Map *map)
{
	if (map != NULL)
	{
		if (map->graph != NULL)
			free(map->graph);
		if (map->map_index != NULL)
			free(map->map_index);
		free(map);
		map = NULL;
	}
}


char* map_marshal(Map *map)
{
	int i,j,pos;
	char *buffer = (char*)malloc(MAX_LINE_LENGTH*sizeof(char)*(map->n + 2));
	if (buffer == NULL)
	{
		printf("failed allocating buffer for map marshal\n");
		return NULL;
	}

	pos = sprintf(buffer,"%d\n",map->n);
	for (i=0; i<map->n; i++)
	{
		pos = pos + sprintf(buffer + pos,"%d %d ",map->map_index[i].x,map->map_index[i].y);
	}
	sprintf(buffer + pos - 1,"\n"); //replace space with line end
	for (i=0; i<(map->n); i++)
	{
		for (j=0; j<(map->n); j++)
		{	
			pos = pos + sprintf(buffer + pos,"%d ", GRAPH(i,j));
		}
		sprintf(buffer + pos - 1,"\n");
	}
	return buffer;
}


Map *map_unmarshal(char *buf)
{
	char *token;
	char newline[] = "\n";
	char space[] = " ";
	int n;
	int i,j;
	Map *map = NULL;

	if (buf==NULL)
	{
		printf("bad buffer argument\r\n");
		return NULL;
	}
	token = strtok(buf, newline);
	n = atoi(token);
	map = map_init(n);
	if (map == NULL)
	{
		return NULL;
	}
	for (i=0; i<(n-1); i++)
	{
		token = strtok(NULL, space);
		map->map_index[i].ind = i;
		map->map_index[i].x = atoi(token);
		token = strtok(NULL, space);
		map->map_index[i].y = atoi(token);
	}
	token = strtok(NULL, space);
	map->map_index[i].ind = i;
	map->map_index[i].x = atoi(token);
	token = strtok(NULL, newline);
	map->map_index[i].y = atoi(token);
	for (i=0; i<n; i++)
	{
		for (j=0; j<(n-1); j++)
		{
			token = strtok(NULL, space);

			GRAPH(i,j) = atoi(token);
			//printf("%d ", atoi(token));
		}
		token = strtok(NULL, newline);

		GRAPH(i,j) = atoi(token);
		//printf("%d ", atoi(token));
		//printf("\n");
	}
	return map;
}

Map *LoadMapFromFile(char *graphTxt)
{
	FILE *graphFile;
	long fsize;
	char *string = NULL;
	Map *map = NULL;

	graphFile = fopen(graphTxt,"r");
	if (graphFile == NULL)
	{
		printf("Cannot open graph file as specified: %s\r\n",graphTxt);
		return NULL;
	}
	fseek(graphFile, 0, SEEK_END);
	fsize = ftell(graphFile);
	fseek(graphFile, 0, SEEK_SET);

	string = (char *)malloc(fsize + 1);
	if (string == NULL)
	{
		printf("Cannot allocate mem to read graph file");
		return NULL;
	}
	fread(string, fsize, 1, graphFile);
	fclose(graphFile);

	string[fsize] = 0;
	map = map_unmarshal(string);
	free(string);
	return map;
}

int UpdateMap(char* recievedStr, Map *map, FILE *log_file, int Ind)
{
	int netInd[2],newWeight,oldWeight,D;
	Node *node_from = NULL,*node_to = NULL;
	sscanf(recievedStr,"%d %d %d",&netInd[0],&netInd[1],&D);
	oldWeight = GRAPH(netInd[0],netInd[1]);
	newWeight = 1 + (((3*oldWeight + D) - 1) / 4);
	GRAPH(netInd[0],netInd[1]) = newWeight;
	GRAPH(netInd[1],netInd[0]) = newWeight;
	node_from = map_i2c(map,netInd[0]);
	node_to = map_i2c(map,netInd[1]);
	writeLogAndScreen(log_file,"Client %d reported %d %d %d %d %d new weight is %d\n",Ind+1,node_from->x,node_from->y,node_to->x,node_to->y,D,newWeight);
	return 0;
}

void map_print(Map *map,FILE *file)
{
	int i,j;
	writeLogAndScreen(file,"%d\n",map->n);
	for (i=0; i<map->n; i++)
	{
		writeLogAndScreen(file,"%d %d",map->map_index[i].x,map->map_index[i].y);
		if (i == map->n -1)
			writeLogAndScreen(file,"\n");
		else
			writeLogAndScreen(file," ");
	}
	for (i=0; i<(map->n); i++)
	{
		for (j=0; j<(map->n); j++)
		{	
			writeLogAndScreen(file,"%d", GRAPH(i,j));
			if (j == map->n -1)
			{
				if (i != map->n -1)
					writeLogAndScreen(file,"\n");
			}
			else
				writeLogAndScreen(file," ");
		}
	}
}


Node *map_i2c(Map *map, int ind)
{
	if (( map == NULL ) || ( ind >= map->n ) || (ind < 0) )
		return NULL; 
	return &(map->map_index[ind]);
}


int map_c2i(Map *map, Node *node)
{
	int i;
	if ( map != NULL )
	{	
		for (i=0; i < map->n; i++)
		{
			if ( map_nodecmp(node, &(map->map_index[i])) == 0)
				return i;
		}
	}
	return -1;
}


int map_nodecmp(Node *node1, Node *node2)
{
	if ((node1->x == node2->x) && (node1->y == node2->y))
		return 0;
	else
		return 1;
}
